#include <iostream>
#include <string>
#include <list>
#include<cstdlib>

typedef std::string STATE;

class Flyweight
{
public:
    virtual ~Flyweight()
	{
		std::cout<<__FUNCTION__<<std::endl;
	}

    STATE GetIntrinsicState()
	{
		return m_State;
	}
    virtual void Operation(STATE& ExtrinsicState) = 0;

protected:
    Flyweight(const STATE& state):m_State(state)
    {
		std::cout<<__FUNCTION__<<std::endl;
    }

private:
    STATE m_State;
};

class ConcreateFlyweight: public Flyweight
{
public:
    ConcreateFlyweight(const STATE& state):Flyweight(state)
    {
		std::cout<<__FUNCTION__<<std::endl;
    }
    virtual ~ConcreateFlyweight()
	{
		std::cout<<__FUNCTION__<<std::endl;
	}

    virtual void Operation(STATE& ExtrinsicState)
	{
		std::cout<<__FUNCTION__<<std::endl;
	}
};

class FlyweightFactory
{
public:
    FlyweightFactory()
	{
		std::cout<<__FUNCTION__<<std::endl;
	}

	~FlyweightFactory()
	{
		std::list<Flyweight*>::iterator iter1, iter2, temp;

		for (iter1 = m_listFlyweight.begin(), iter2 = m_listFlyweight.end();
			iter1 != iter2;
			)
		{
			temp = iter1;
			++iter1;
			delete (*temp);
		}

		m_listFlyweight.clear();
	}

	Flyweight* GetFlyweight(const STATE& key)
	{
		std::list<Flyweight*>::iterator iter1, iter2;

		for (iter1 = m_listFlyweight.begin(), iter2 = m_listFlyweight.end();iter1 != iter2;++iter1)
		{
			if ((*iter1)->GetIntrinsicState() == key)
			{
				std::cout << "The Flyweight:" << key << " already exits"<< std::endl;
				return (*iter1);
			}
		}

		std::cout << "Creating a new Flyweight:" << key << std::endl;
		Flyweight* flyweight = new ConcreateFlyweight(key);
		m_listFlyweight.push_back(flyweight);
		return flyweight;
	}

private:
    std::list<Flyweight*>    m_listFlyweight;
};

int main()
{
    FlyweightFactory flyweightfactory;
    flyweightfactory.GetFlyweight("hello");
    flyweightfactory.GetFlyweight("world");
    flyweightfactory.GetFlyweight("hello");

    system("pause");
    return 0;
}